package common.util;

import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import com.github.houbb.pinyin.util.PinyinHelper;
import lombok.Data;

import java.io.IOException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PublicPiYin {

    public static void main(String[] args) throws SQLException, IOException {

        Map<String, String> baiJiaXing = getBJX();
        String cnName = "现代生物医学进展";

        String piYi = getFullPiYi(cnName, baiJiaXing);
        System.out.println("piYi: " + piYi);

        String a = "Sun, CY; Zhou, H; Chen, WQ; Li, JN; Xie, LS; Wang, HY; Zhang, GW";
        String b = "Sun, Chuyu; Zhou, Hui; Chen, Weiqing; Li, Junna; Xie, Linshen; Wang, Haiyang; Zhang, Guowei; He, Xiaoping";
        Set<String> aSet = new HashSet<>(Arrays.asList(a.split("; ")));
        Set<String> bSet = new HashSet<>(Arrays.asList(b.split("; ")));
        // aSet 作为邮箱或简写
        List<AuEmScore> auMailScore = PublicPiYin.getAuMailScore(bSet, aSet);
        for (AuEmScore auEmScore : auMailScore) {
            System.out.println("auEmScore: " + auEmScore);
        }

        String c = "ZHANG Peng-peng,XU Xiao-yong,ZHANG Feng,SHI Yi";
//        String c = ",";
        String d = "张鹏鹏,徐小勇,张峰,施毅";

        List<String> cList = new ArrayList<>();
        List<String> dList = new ArrayList<>();
        List<String> cSplit = Arrays.asList(c.split(","));
        List<String> dSplit = Arrays.asList(d.split(","));
        cList.addAll(cSplit);
        dList.addAll(dSplit);
        Map<String, List<String>> duoYinZiMap = getDuoYinZiMap();
        List<AuthInfo> authInfos = mergeAuthor(cList, dList, duoYinZiMap, baiJiaXing);
        for (AuthInfo authInfo : authInfos) {
            System.out.println("authInfo: " + authInfo);
        }


    }

    @Data
    public static class AuEmScore {
        private String au;
        private String em;
        private Double score;
    }

    public static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);
        return m.find();
    }

    //删除拼音中的音调 2022.03.14 认定此为标准
    public static String rePy(String str) {
        return str.toLowerCase().replace("ā", "a").replace("à", "a").replace("á", "a").replace("ǎ", "a").replace("ě", "e").replace("é", "e").replace("ē", "e").replace("è", "e")
                .replace("ī", "i").replace("ǐ", "i").replace("ì", "i").replace("í", "i").replace("ó", "o").replace("ō", "o").replace("ǒ", "o").replace("ò", "o")
                .replace("ù", "u").replace("ǔ", "u").replace("ū", "u").replace("ú", "u").replace("ü", "u").replace("ǚ", "u").replace("ǜ", "u").replace("ǖ", "u")
                .replace("ǘ", "u").replace("ń", "n").replace("\uE7C8", "n").replace("ň", "n").replace("ɡ", "g").replaceAll(" +", " ").trim();
    }

    //获取拼音：翁彦琴-> weng yanqin
    public static String getPiYi(String cnName, Map<String, String> baiJiaXing) {
        if (!isContainChinese(cnName)) {
            return cnName;
        }
        if (cnName.length() < 2) {
            return rePy(PinyinHelper.toPinyin(cnName));
        }
        String piYi = "";
        for (Map.Entry<String, String> entry : baiJiaXing.entrySet()) {
            if (cnName.startsWith(entry.getKey())) {
                String mapKey = entry.getKey();
                String fanYi = cnName.substring(cnName.indexOf(mapKey) + mapKey.length());
                piYi = entry.getValue() + " " + rePy(PinyinHelper.toPinyin(fanYi)).replaceAll(" +", "");
                break;
            }
        }
        if (piYi.length() < 1) {
            piYi = rePy(PinyinHelper.toPinyin(cnName.substring(0, 1))) + " " + rePy(PinyinHelper.toPinyin(cnName.substring(1))).replaceAll(" +", "");
        }
        return piYi;
    }

    //获取拼音：翁彦琴-> weng yan qin
    public static String getFullPiYi(String cnName, Map<String, String> baiJiaXing) {
        if (!isContainChinese(cnName)) {
            return cnName;
        }
        if (cnName.length() < 2) {
            return rePy(PinyinHelper.toPinyin(cnName));
        }
        String piYi = "";
        for (Map.Entry<String, String> entry : baiJiaXing.entrySet()) {
            if (cnName.startsWith(entry.getKey())) {
                String mapKey = entry.getKey();
                String fanYi = cnName.substring(cnName.indexOf(mapKey) + mapKey.length());
                piYi = entry.getValue() + " " + rePy(PinyinHelper.toPinyin(fanYi)).replaceAll(" +", " ").trim();
                break;
            }
        }
        if (piYi.length() < 1) {
            piYi = rePy(PinyinHelper.toPinyin(cnName.substring(0, 1))) + " " + rePy(PinyinHelper.toPinyin(cnName.substring(1))).replaceAll(" +", " ").trim();
        }
        return piYi;
    }

    //获取简写的拼音：翁彦琴-> weng yq
    public static String getSimpPiYin(String cnName, Map<String, String> baiJiaXing) {
        if (!isContainChinese(cnName)) {
            return cnName;
        }
        Map<String, String> nullMap = new HashMap<>();
        String simpPiYin = "";
        List<String> list = Arrays.asList(cnName.replace(" ", "").split(""));
        String last = "";
        StringBuilder name = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            if (i == 0) {
                if (isContainChinese(s)) {
                    last = getPiYi(s, baiJiaXing);
                } else {
                    last = rePy(s);
                }
            } else {
                if (isContainChinese(s)) {
                    name.append(getPiYi(s, nullMap).substring(0, 1));
                } else {
                    name.append(rePy(s));
                }
            }
        }
        simpPiYin = last + " " + name.toString();
        return simpPiYin;
    }

    public static int getListStrLen(List<String> enAuthList) {
        int len = 0;
        for (String enAuth : enAuthList) {
            len += enAuth.trim().length();
        }
        return len;
    }

    public static String strSort(String str) {
        char[] s1 = str.toCharArray();
        for (int i = 0; i < s1.length; i++) {
            for (int j = 0; j < i; j++) {
                if (s1[i] < s1[j]) {
                    char temp = s1[i];
                    s1[i] = s1[j];
                    s1[j] = temp;
                }
            }
        }
        String st = new String(s1);
        return st;
    }

    // 去作者的空格，统一的标准。
    public static String authorBlankSpace(String auth) {
        return auth.replace("\uE3C7", "").replace("\uE492", "").replace("\uE3A3", "").replace("\uE1DD", "").replace("\uE09C", "").replace("\uE0B0", "").replace("-", "").replace(",", "").replace(".", "").replaceAll(" +", "").replace("  ", "").replace(" ", "").toLowerCase().trim();
    }


    // 合并作者，此方法考虑了多音字的问题，并增加了容错，允许1个字符不相同的也可以合并到一起。输入中、英作者的List以及多音字Map，输出中、英对照的作者清单。
    public static List<AuthInfo> mergeAuthor(List<String> enAuthList, List<String> cnAuthList, Map<String, List<String>> duoYinZiMap, Map<String, String> baiJiaXing) {
        Set<String> authSet = new HashSet<>();
        // 如果没有英文的作者，则使用拼音。
//        System.out.println("enAuthList: " + enAuthList.size() + " cnAuthList: " + cnAuthList.size());
        if (getListStrLen(enAuthList) < 1 && getListStrLen(cnAuthList) > 1) {
            enAuthList.clear();
            for (String cnAuth : cnAuthList) {
                enAuthList.add(getFullPiYi(cnAuth, baiJiaXing));
            }
        }
        for (String auth : enAuthList) {
            if (auth.length() > 1) {
                authSet.add(auth);
            }
        }
        for (String auth : cnAuthList) {
            if (auth.length() > 1) {
                authSet.add(auth);
            }
        }
        Map<String, String> piYinListAndCnAuMap = new HashMap<>();
        Map<String, String> enAuListAndEnAuMap = new HashMap<>();
        Set<String> allAuthSet = new HashSet<>();
        Set<String> onlySet = new HashSet<>();
        List<AuthInfo> authList = new ArrayList<>();
        if (cnAuthList.size() > 0 && enAuthList.size() > 0) {
            for (String auth : authSet) {
                String str = auth.toLowerCase().replaceAll(" +", "");
                if (!onlySet.contains(str)) {
                    onlySet.add(str);
                    allAuthSet.add(auth.replace("  ", " "));
                }
                if (isContainChinese(auth)) {
                    if (auth.trim().length() > 1) {
                        Set<String> namePiYin = getNamePiYin(auth, duoYinZiMap);
                        for (String s : namePiYin) {
                            piYinListAndCnAuMap.put(strSort(authorBlankSpace(s)), auth);
                        }
                    }
                } else {
                    if (auth.length() > 3) {
                        enAuListAndEnAuMap.put(strSort(authorBlankSpace(auth)), auth.replace("  ", " "));
                    }
                }
            }
            for (Map.Entry<String, String> entry : enAuListAndEnAuMap.entrySet()) {
                String key = entry.getKey();
                String enAuth = entry.getValue().replace("  ", " ");
                if (piYinListAndCnAuMap.containsKey(key)) {
                    String cnAuth = piYinListAndCnAuMap.get(key);
                    allAuthSet.remove(cnAuth);
                    allAuthSet.remove(enAuth);
                    AuthInfo authInfo = new AuthInfo();
                    authInfo.setCnAuth(cnAuth);
                    authInfo.setEnAuth(enAuth);
                    authList.add(authInfo);
                } else {
                    for (Map.Entry<String, String> piYin : piYinListAndCnAuMap.entrySet()) {
                        String cnAuth = piYin.getValue();
                        if (almostEquals(key, piYin.getKey())) {
                            allAuthSet.remove(cnAuth);
                            allAuthSet.remove(enAuth);
                            AuthInfo authInfo = new AuthInfo();
                            authInfo.setCnAuth(cnAuth);
                            authInfo.setEnAuth(enAuth);
                            authList.add(authInfo);
                            break;
                        }
                    }
                }
            }
            for (String auth : allAuthSet) {
                AuthInfo authInfo = new AuthInfo();
                if (isContainChinese(auth)) {
                    authInfo.setCnAuth(auth);
                } else {
                    authInfo.setEnAuth(auth);
                }
                authList.add(authInfo);
            }
            return authList;
        }
        for (String auth : authSet) {
            AuthInfo authInfo = new AuthInfo();
            if (isContainChinese(auth)) {
                authInfo.setCnAuth(auth);
            } else {
                authInfo.setEnAuth(auth);
            }
            authList.add(authInfo);
        }
        return authList;
    }

    public static Map<Integer, Integer> mapSortValueIntMin(Map<Integer, Integer> mapName) {
        Map<Integer, Integer> result = new LinkedHashMap<>();
        mapName.entrySet().stream()
                .sorted(Map.Entry.<Integer, Integer>comparingByValue())
                .forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        return result;
    }

    // 邮箱与各作者之间的相似度得分。也可以当作全写的作者与简写的作者之间的匹配。
    public static List<AuEmScore> getAuMailScore(Set<String> nameSet, Set<String> mailSet) {
        List<AuEmScore> list = new ArrayList<>();
        if (nameSet.size() == 1 && mailSet.size() == 1) {
            AuEmScore auEmScore = new AuEmScore();
            auEmScore.setAu(setChangeStr(nameSet));
            auEmScore.setEm(setChangeStr(mailSet));
            auEmScore.setScore(0.91);
            list.add(auEmScore);
            return list;
        }
        if (nameSet.size() < 1 && mailSet.size() > 0) {
            for (String mail : mailSet) {
                AuEmScore auEmScore = new AuEmScore();
                auEmScore.setAu("");
                auEmScore.setEm(mail);
                auEmScore.setScore(0.0);
                list.add(auEmScore);
            }
            return list;
        }
        if (nameSet.size() > 0 && mailSet.size() < 1) {
            for (String name : nameSet) {
                AuEmScore auEmScore = new AuEmScore();
                auEmScore.setAu(name);
                auEmScore.setEm("");
                auEmScore.setScore(0.0);
                list.add(auEmScore);
            }
            return list;
        }
        Map<String, Double> zuHeMap = new ConcurrentHashMap<>();
        String spl = "ζłξ";
        for (String author : nameSet) {
            int lenFrom = author.length();
            Set<String> fromSet = getMaxStrSet(author);
            for (String mail : mailSet) {
                String save = mail.split("@")[0];
                int lenSave = save.length();
                Set<String> saveSet = getMaxStrSet(save);

                // 邮箱和作者字符的相似度
                double textSimilarity = getSimilarityRatio(strSort(save), strSort(author));

                // 作者包含邮箱字符的个数
                int authContainMailNum = 0;
                for (int i = 0; i < author.length(); i++) {
                    if (save.contains(author.split("")[i])) {
                        authContainMailNum++;
                    }
                }
                double authContainMailScore = 0.0;
                if (lenFrom > 0) {
                    authContainMailScore = Arith.mul(Arith.div(authContainMailNum, lenFrom), 1.0);
                }

                // 邮箱包含作者字符的个数
                int mailContainAuthNum = 0;
                for (int j = 0; j < save.length(); j++) {
                    if (author.contains(save.split("")[j])) {
                        mailContainAuthNum++;
                    }
                }
                double mailContainAuthScore = 0.0;
                if (lenSave > 0) {
                    mailContainAuthScore = Arith.mul(Arith.div(mailContainAuthNum, lenSave), 1.0);
                }

                // 邮箱与作者连续相同的最大字符数
                int mailContinuousSameAuthNum = 1;
                for (String str : saveSet) {
                    if (fromSet.contains(str)) {
                        if (str.length() > mailContinuousSameAuthNum) {
                            mailContinuousSameAuthNum = str.length();
                        }
                    }
                }
                double ContinuousSameScore1 = 0.0;
                if (lenFrom > 0) {
                    ContinuousSameScore1 = Arith.mul(Arith.div(mailContinuousSameAuthNum, lenFrom), 0.5);
                }

                // 作者与邮箱连续相同的最大字符数
                int authContinuousSameMailNum = 1;
                for (String str : fromSet) {
                    if (saveSet.contains(str)) {
                        if (str.length() > authContinuousSameMailNum) {
                            authContinuousSameMailNum = str.length();
                        }
                    }
                }
                double ContinuousSameScore2 = 0.0;
                if (lenSave > 0) {
                    ContinuousSameScore2 = Arith.mul(Arith.div(authContinuousSameMailNum, lenSave), 0.5);
                }

                // 总得分
                double score = Arith.div((textSimilarity + authContainMailScore + mailContainAuthScore + ContinuousSameScore1 + ContinuousSameScore2), 4);

                String zuHe = author + spl + mail;
                zuHeMap.put(zuHe, score);
            }
        }

        if (zuHeMap.size() > 0) {
            Set<String> auNameSet = new ConcurrentHashSet<>();
            Set<String> auMailSet = new ConcurrentHashSet<>();
            Map<String, Double> auMailScoreMap = mapSortValue(zuHeMap);
            for (Map.Entry<String, Double> entity : auMailScoreMap.entrySet()) {
                String name = entity.getKey();
                if (name.contains(spl) && name.split(spl).length > 1) {
                    String auName = name.split(spl)[0];
                    String auMail = name.split(spl)[1];
                    Double score = entity.getValue();
                    if (!auNameSet.contains(auName) && !auMailSet.contains(auMail)) {
                        AuEmScore auEmScore = new AuEmScore();
                        auEmScore.setAu(auName);
                        auEmScore.setEm(auMail);
                        auEmScore.setScore(score);
                        list.add(auEmScore);
                        auMailSet.add(auMail);
                        auNameSet.add(auName);
                    }
                }
            }
            for (Map.Entry<String, Double> entity : auMailScoreMap.entrySet()) {
                String name = entity.getKey();
                if (name.contains(spl) && name.split(spl).length > 1) {
                    String auName = name.split(spl)[0];
                    String auMail = name.split(spl)[1];
                    Double score = entity.getValue();
                    if (!auNameSet.contains(auName) && auMailSet.contains(auMail)) {
                        AuEmScore auEmScore = new AuEmScore();
                        auEmScore.setAu(auName);
                        auEmScore.setEm("");
                        auEmScore.setScore(0.0);
                        list.add(auEmScore);
                        auNameSet.add(auName);
                    }
                    if (auNameSet.contains(auName) && !auMailSet.contains(auMail)) {
                        AuEmScore auEmScore = new AuEmScore();
                        auEmScore.setAu("");
                        auEmScore.setEm(auMail);
                        auEmScore.setScore(0.0);
                        list.add(auEmScore);
                        auMailSet.add(auMail);
                    }
                }
            }
        }
        return list;
    }

    public static Map<String, Double> mapSortValue(Map<String, Double> mapName) {
        Map<String, Double> result = new LinkedHashMap<>();
        mapName.entrySet().stream()
                .sorted(Map.Entry.<String, Double>comparingByValue()
                        .reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        return result;
    }

    public static class Arith {
        //默认除法运算精度
        private static final int DEF_DIV_SCALE = 6;

        //构造器私有化，让这个类不能实例化
        private Arith() {
        }

        //提供精确的加法运算
        public static double add(double v1, double v2) {
            BigDecimal b1 = BigDecimal.valueOf(v1);
            BigDecimal b2 = BigDecimal.valueOf(v2);
            return b1.add(b2).doubleValue();
        }

        //精确的减法运算
        public static double sub(double v1, double v2) {
            BigDecimal b1 = BigDecimal.valueOf(v1);
            BigDecimal b2 = BigDecimal.valueOf(v2);
            return b1.subtract(b2).doubleValue();
        }

        //精确的乘法运算
        public static double mul(double v1, double v2) {
            BigDecimal b1 = BigDecimal.valueOf(v1);
            BigDecimal b2 = BigDecimal.valueOf(v2);
            return b1.multiply(b2).doubleValue();
        }

        //提供（相对）精确的除法运算，当发生除不尽的情况时，精确到小数点后10位的数字四舍五入
        public static double div(double v1, double v2) {
            BigDecimal b1 = BigDecimal.valueOf(v1);
            BigDecimal b2 = BigDecimal.valueOf(v2);
            return b1.divide(b2, DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue();
        }
    }

    //获取两字符串的相似度_1
    public static double getSimilarityRatio(String str, String target) {
        int max = Math.max(str.length(), target.length());
        return 1 - (double) compare(str, target) / max;
    }

    //获取两字符串的相似度_2 两字符串相似度计算算法 Levenshtein Distance编辑距离算法
    private static int compare(String str, String target) {
        int d[][];
        int n = str.length();
        int m = target.length();
        int i;
        int j;
        char ch1;
        char ch2;
        int temp;
        if (n == 0) {
            return m;
        }
        if (m == 0) {
            return n;
        }
        d = new int[n + 1][m + 1];
        for (i = 0; i <= n; i++) {
            d[i][0] = i;
        }
        for (j = 0; j <= m; j++) {
            d[0][j] = j;
        }
        for (i = 1; i <= n; i++) {
            ch1 = str.charAt(i - 1);
            for (j = 1; j <= m; j++) {
                ch2 = target.charAt(j - 1);
                if (ch1 == ch2 || ch1 == ch2 + 32 || ch1 + 32 == ch2) {
                    temp = 0;
                } else {
                    temp = 1;
                }
                d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + temp);
            }
        }
        return d[n][m];
    }

    //获取两字符串的相似度_3
    private static int min(int one, int two, int three) {
        return (one = Math.min(one, two)) < three ? one : three;
    }

    // 返回字符串最多的连续组合
    public static Set<String> getMaxStrSet(String str) {
        Set<String> set = new HashSet<>();
        for (int i = 0; i < str.length(); i++) {
            for (int j = str.length(); j > 1; j--) {
                if (j >= i) {
                    String temp = str.substring(i, j);
                    if (temp.length() > 1) {
                        set.add(temp);
                    }
                }
            }
        }
        return set;
    }

    // 将只有一个值的set转换为String输出
    public static String setChangeStr(Set<String> set) {
        if (set.size() == 1) {
            for (String s : set) {
                if (null != s && s.length() > 1) {
                    return s;
                }
            }
        }
        return "";
    }

    // 相似作者，只允许相差一个字符，且大于6位，要求长的全部包含短的。比如：sun shuming -> sun shumin
    private static Boolean almostEquals(String from, String save) {
        if (isContainChinese(from) || isContainChinese(save) || from.length() < 4 || save.length() < 4) {
            return false;
        }
        from = from.toLowerCase().replaceAll(" +", "");
        save = save.toLowerCase().replaceAll(" +", "");
        String len = from;
        String[] list = save.split("");
        if (save.length() > from.length() && from.length() > 6) {
            len = save;
            list = from.split("");
        }
        if (Math.abs(save.length() - from.length()) == 1) {
            for (String s : list) {
                if (!len.contains(s)) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    // 获取汉字的全拼和简拼形式，若是多音字，也给返回。比如：刘长玲 -> [liu zl, liu chang ling, liu zhang ling, liu cl]
    private static Set<String> getNamePiYin(String auth, Map<String, List<String>> duoYinZiMap) {
        String[] nameList = auth.replaceAll(" +", "").replace(" ", "").split("");
        List<List<String>> input = new ArrayList<>();
        for (String str : nameList) {
            List<String> list = new ArrayList<>();
            if (duoYinZiMap.containsKey(str)) {
                list.addAll(duoYinZiMap.get(str));
            } else {
                list.add(rePy(PinyinHelper.toPinyin(str)));
            }
            input.add(list);
        }
        List<List<String>> output = new ArrayList<>();
        descartes(input, output, 0, new ArrayList<>());
        Set<String> result = new HashSet<>();
        for (List<String> list : output) {
            String name = String.join(" ", list);
            StringBuilder fuXing = new StringBuilder(isFuXing(name) + " ");
            if (fuXing.length() > 1 && name.length() > fuXing.length()) {
                String after = name.substring(fuXing.length()).trim();
                result.add(fuXing.toString() + after);
                String[] end = after.split(" ");
                for (String s : end) {
                    if (s.length() > 0) {
                        fuXing.append(s.substring(0, 1));
                    }
                }
                result.add(fuXing.toString());
            } else {
                result.add(name);
                String[] end = name.split(" ");
                StringBuilder str = new StringBuilder();
                for (int i = 0; i < end.length; i++) {
                    if (i == 0) {
                        str = new StringBuilder(end[i] + " ");
                    } else {
                        if (end[i].length() > 0) {
                            str.append(end[i].substring(0, 1));
                        }
                    }
                }
                result.add(str.toString());
            }
        }
        return result;
    }

    // 部分复姓：百里、单于、东郭、公孙、呼延、皇甫、令狐、慕容、南郭、欧阳、司马、司空、司徒、上官、拓拔、完颜、西门、夏侯、轩辕、耶律、尉迟、宇文、子车、诸葛。
    public static String isFuXing(String name) {
        if (name.startsWith("bai li")) {
            return "baili";
        }
        if (name.startsWith("chan yu")) {
            return "chanyu";
        }
        if (name.startsWith("dong guo")) {
            return "dongguo";
        }
        if (name.startsWith("gong sun")) {
            return "gongsun";
        }
        if (name.startsWith("hu yan")) {
            return "huyan";
        }
        if (name.startsWith("huang fu")) {
            return "huangfu";
        }
        if (name.startsWith("ling hu")) {
            return "linghu";
        }
        if (name.startsWith("mu rong")) {
            return "murong";
        }
        if (name.startsWith("nan guo")) {
            return "nanguo";
        }
        if (name.startsWith("ou yang")) {
            return "ouyang";
        }
        if (name.startsWith("si ma")) {
            return "sima";
        }
        if (name.startsWith("si kong")) {
            return "sikong";
        }
        if (name.startsWith("si tu")) {
            return "situ";
        }
        if (name.startsWith("shang guan")) {
            return "shangguan";
        }
        if (name.startsWith("tuo ba")) {
            return "tuoba";
        }
        if (name.startsWith("wan yan")) {
            return "wanyan";
        }
        if (name.startsWith("xi men")) {
            return "ximen";
        }
        if (name.startsWith("xia hou")) {
            return "xiahou";
        }
        if (name.startsWith("xuan yuan")) {
            return "xuanyuan";
        }
        if (name.startsWith("ye lv")) {
            return "yelv";
        }
        if (name.startsWith("yu chi")) {
            return "yuchi";
        }
        if (name.startsWith("yu wen")) {
            return "yuwen";
        }
        if (name.startsWith("zi ju")) {
            return "ziju";
        }
        if (name.startsWith("zhu ge")) {
            return "zhuge";
        }
        return "";
    }

    // 笛卡尔积运算，用于获取多音字的名字组合，比如：种长，先将名字转为[[zhong, chong], [chang, zhang]]输入，result是结果的输出，layer为层数，默认为0，curList为中间结果，可以输入new ArrayList<>()。
    private static void descartes(List<List<String>> input, List<List<String>> result, int layer, List<String> curList) {
        if (layer < input.size() - 1) {
            if (input.get(layer).size() == 0) {
                descartes(input, result, layer + 1, curList);
            } else {
                for (int i = 0; i < input.get(layer).size(); i++) {
                    List<String> list = new ArrayList<>(curList);
                    list.add(input.get(layer).get(i));
                    descartes(input, result, layer + 1, list);
                }
            }
        } else if (layer == input.size() - 1) {
            if (input.get(layer).size() == 0) {
                result.add(curList);
            } else {
                for (int i = 0; i < input.get(layer).size(); i++) {
                    List<String> list = new ArrayList<>(curList);
                    list.add(input.get(layer).get(i));
                    result.add(list);
                }
            }
        }
    }

    // 往原表里需要更新的部分
    @Data
    public static class AuthInfo {
        private String enAuth = "";
        private String cnAuth = "";
    }

    public static String getStrField(Entity entry, String field) {
        if (null != entry) {
            String str = entry.getStr(field);
            if (null != str && str.length() > 0 && !str.toLowerCase().trim().equals("null")) {
                return str.trim();
            }
        }
        return "";
    }

    public static void putStrSetStr(String name, String str, Map<String, Set<String>> strSetStrMap) {
        if (name.length() > 0 && str.length() > 0) {
            strSetStrMap.compute(name, (k, v) -> {
                if (v == null) {
                    v = new ConcurrentHashSet<>();
                }
                v.add(str);
                return v;
            });
        }
    }

    // 获取多音字，Map结构为键为汉字，值为多个拼音的List，比如：缪 -> [mou, miu, mu, miao, liao]
    public static Map<String, List<String>> getDuoYinZiMap() throws SQLException {
        String helpTable = "scholar.help_duo_yin_zi_da_quan";
        List<Entity> tableData = Db.use().query("select `han_zi`,`pi_yin` from " + helpTable);
        Map<String, Set<String>> map = new ConcurrentHashMap<>();
        for (Entity entry : tableData) {
            if (null != entry) {
                String hanZi = getStrField(entry, "han_zi");
                String piYin = rePy(getStrField(entry, "pi_yin")).replace(" ", "").replace("(", "").replace(")", "");
                if (piYin.length() > 0 && hanZi.length() > 0) {
                    String[] list = piYin.split("/");
                    for (String str : list) {
                        putStrSetStr(hanZi, str, map);
                    }
                }
            }
        }
        Map<String, List<String>> duoYinZiMap = new ConcurrentHashMap<>();
        for (Map.Entry<String, Set<String>> entry : map.entrySet()) {
            if (entry.getValue().size() > 1) {
                duoYinZiMap.put(entry.getKey(), new ArrayList<>(entry.getValue()));
            }
        }
        return duoYinZiMap;
    }

    //获取百家姓
    public static Map<String, String> getBJX() {
        Map<String, String> map = new HashMap<>();
        map.put("薄", "bo");
        map.put("卜", "bu");
        map.put("曾", "zeng");
        map.put("查", "zha");
        map.put("仇", "qiu");
        map.put("单", "shan");
        map.put("都", "du");
        map.put("佴", "nai");
        map.put("皇甫", "huangpu");
        map.put("解", "xie");
        map.put("阚", "kan");
        map.put("乐", "yue");
        map.put("乐正", "yuezheng");
        map.put("缪", "miao");
        map.put("能", "nai");
        map.put("乜", "nie");
        map.put("拓跋", "tuoba");
        map.put("翟", "zhai");
        map.put("子车", "ziju");
        return map;
    }

}
